package remote

import (
	"common/logs"
	"connector/protocol"
	"encoding/json"
	"sync"
)

type Session struct {
	sync.RWMutex
	client          Client
	Msg             *Msg
	pushChan        chan *PushUserMsg
	data            map[string]any
	pushSessionChan chan map[string]any
}

type PushMsg struct {
	data   []byte
	router string
}

type PushUserMsg struct {
	PushMsg *PushMsg `json:"pushMsg"`
	Users   []string `json:"users"`
}

// Push 推送消息
func (s *Session) Push(users []string, data any, router string) {
	marshal, _ := json.Marshal(data)
	upm := &PushUserMsg{
		Users: users,
		PushMsg: &PushMsg{
			data:   marshal,
			router: router,
		},
	}
	s.pushChan <- upm
}

func (s *Session) pushChangeRead() {
	for {
		select {
		case data := <-s.pushChan:
			pushMessage := protocol.Message{
				Type:  protocol.Push,
				ID:    s.Msg.Body.ID,
				Data:  data.PushMsg.data,
				Route: data.PushMsg.router,
			}
			msg := &Msg{
				Dst:      s.Msg.Src,
				Src:      s.Msg.Dst,
				Body:     &pushMessage,
				Cid:      s.Msg.Cid,
				Uid:      s.Msg.Uid,
				PushUser: data.Users,
			}
			marshal, _ := json.Marshal(msg)
			if err := s.client.SendMsg(msg.Dst, marshal); err != nil {
				logs.Error("推送消息错误：%v，msg：%v", err, msg)
			}
		}
	}
}

func (s *Session) Put(key, value string) {
	s.Lock()
	defer s.Unlock()
	s.data[key] = value
	s.pushSessionChan <- s.data
}

func (s *Session) pushSessionRead() {
	for {
		select {
		case data := <-s.pushSessionChan:
			msg := &Msg{
				Dst:         s.Msg.Src,
				Src:         s.Msg.Dst,
				Cid:         s.Msg.Cid,
				Uid:         s.Msg.Uid,
				SessionData: data,
				Type:        SessionType,
			}
			marshal, _ := json.Marshal(msg)
			if err := s.client.SendMsg(msg.Dst, marshal); err != nil {
				logs.Error("推送消息错误：%v，msg：%v", err, msg)
			}
		}
	}
}

func (s *Session) SetData(data map[string]any) {
	s.Lock()
	defer s.Unlock()
	s.data = data
}

func (s *Session) GetData(key string) (any, bool) {
	s.Lock()
	defer s.Unlock()
	value, ok := s.data[key]
	return value, ok
}

func NewSession(client Client, msg *Msg) *Session {
	session := &Session{
		client:          client,
		Msg:             msg,
		pushChan:        make(chan *PushUserMsg, 1024),
		data:            make(map[string]any),
		pushSessionChan: make(chan map[string]any, 1024),
	}
	go session.pushChangeRead()
	go session.pushSessionRead()
	return session
}
